﻿using AutoMapper;
using DTcms.Core.Common.Emum;
using DTcms.Core.Common.Helper;
using DTcms.Core.DBFactory.Database;
using DTcms.Core.IServices;
using DTcms.Core.Model.Models;
using DTcms.Core.Common.Extensions;
using DTcms.Core.Model.ViewModels;
using System.Linq.Expressions;
using Microsoft.EntityFrameworkCore;

namespace DTcms.Core.Services
{
    /// <summary>
    /// 文章评论接口实现
    /// </summary>
    public class ArticleCommentService : BaseService, IArticleCommentService
    {
        private readonly IMapper _mapper;
        private readonly IUserService _userService;
        private readonly IArticleService _articleService;
        private readonly IMemberService _memberService;

        public ArticleCommentService(IDbContextFactory contentFactory, IMapper mapper, 
            IUserService userService, IArticleService articleService ,IMemberService memberService) : base(contentFactory)
        {
            _mapper = mapper;
            _userService = userService;
            _articleService = articleService;
            _memberService = memberService;
        }

        /// <summary>
        /// 查询一条记录
        /// </summary>
        public async Task<ArticleComment?> QueryAsync(Expression<Func<ArticleComment, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = await _context.Set<ArticleComment>()
                .Include(x => x.User).ThenInclude(x => x!.Member)
                .FirstOrDefaultAsync(funcWhere);
            return result;
        }

        /// <summary>
        /// 根据条件删除一条记录
        /// </summary>
        public async Task<bool> DeleteAsync(Expression<Func<ArticleComment, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var list = await _context.Set<ArticleComment>().Include(x => x.CommentLikes)
                .Where(funcWhere).ToListAsync();
            if (list == null) return false;
            _context.Set<ArticleComment>().RemoveRange(list);
            return await this.SaveAsync();
        }

        /// <summary>
        /// 软删除一条数据
        /// </summary>
        public async Task<bool> MarkDeleteAsync(Expression<Func<ArticleComment, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Write)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var list = await _context.Set<ArticleComment>().Where(funcWhere).ToListAsync();
            if (list == null) return false;
            foreach (var modelt in list)
            {
                modelt.IsDelete = 1;
                _context.Set<ArticleComment>().Attach(modelt);
            }
            return await this.SaveAsync();
        }

        /// <summary>
        /// 添加一条数据
        /// </summary>
        public async Task<ArticleComment?> AddAsync(ArticleCommentAddDto modelDto)
        {
            _context = _contextFactory.CreateContext(WriteRoRead.Write);//连接数据库
            var model = _mapper.Map<ArticleComment>(modelDto);
            var user = await _userService.GetUserAsync();
            if (user == null)
            {
                throw new ResponseException("用户未登录或已超时");
            }
            user.Member = await _memberService.QueryAsync(t => t.UserId == user.Id);
            model.AddTime = DateTime.Now;
            model.UserId = user.Id;
            model.UserName = user.UserName;
            
            //检查文章是否存在
            var articleModel = await _articleService.QueryAsync<Articles>(t => t.Id == modelDto.ArticleId);
            if (articleModel == null) return null;
            model.ChannelId = articleModel.ChannelId;
            //存在父级
            var parentModel = await QueryAsync(t => t.Id == model.ParentId);
            if (parentModel != null)
            {
                //继承父级的RootId
                model.RootId = parentModel.RootId == 0 ? parentModel.Id : parentModel.RootId;
                model.AtUserId = parentModel.UserId;
                model.AtUserName = parentModel.UserName;
            }
            else
            {
                model.RootId = 0;
                model.ParentId = 0;
            }
            //修改评论信息
            await _context.Set<ArticleComment>().AddAsync(model);
            //修改文章评论总数
            Articles article = new();
            article.Id = articleModel.Id;
            article.CommentCount = articleModel.CommentCount + 1;
            var entry = _context.Entry<Articles>(article);
            //设置修改状态
            entry.State = EntityState.Unchanged;
            entry.Property(o => o.CommentCount).IsModified = true;
            //提交保存
            await _context.SaveChangesAsync();
            model.User = user;
            return model;
        }

        /// <summary>
        /// 查询分页列表
        /// </summary>
        public async Task<PaginationList<ArticleComment>> QueryPageAsync(int pageSize, int pageIndex, Expression<Func<ArticleComment, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            var result = _context.Set<ArticleComment>()
                .Include(x => x.User).ThenInclude(x => x!.Member)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            return await PaginationList<ArticleComment>.CreateAsync(pageIndex, pageSize, result);
        }

        /// <summary>
        /// 查询分页列表(树形)
        /// </summary>
        public async Task<PaginationList<ArticleCommentDto>> QueryPageTreeAsync(int pageSize, int pageIndex, Expression<Func<ArticleComment, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //获取第一级的分页数据
            var result = _context.Set<ArticleComment>().Include(x => x.User).ThenInclude(x => x!.Member)
                .Where(x => x.ParentId == 0)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            var page = await PaginationList<ArticleComment>.CreateAsync(pageIndex, pageSize, result);
            //获取所有主键
            List<long> ids = page.Select(t => t.Id).ToList();
            //查询子集数据
            var childrenList = await _context.Set<ArticleComment>().Where(x => ids.Contains(x.RootId)).Where(funcWhere).ToListAsync();
            //将父级填充到子集中
            foreach (var item in page.ToList())
            {
                //检查是否有子集
                if (childrenList != null)
                {
                    childrenList.Add(item);
                }
                else
                {
                    childrenList = page.ToList();
                }
            }
            //生成评论树
            var list = await GetChilds(childrenList, 0, 0, orderBy);
            var pageList = PaginationList<ArticleCommentDto>.Create(pageIndex, pageSize, page.TotalCount, list);
            return pageList;
        }

        /// <summary>
        /// 查询分页列表
        /// </summary>
        public async Task<PaginationList<ArticleCommentDto>> QueryPageFromDtoAsync(int pageSize, int pageIndex, Expression<Func<ArticleComment, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //获取第一级的分页数据
            var result = _context.Set<ArticleComment>().Include(x => x.User).ThenInclude(x => x!.Member)
                .Where(x => x.ParentId == 0)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            var page = await PaginationList<ArticleComment>.CreateAsync(pageIndex, pageSize, result);
            //获取所有主键
            List<long> ids = page.Select(t => t.Id).ToList();
            //查询子集数据
            var childrenList = await _context.Set<ArticleComment>().Where(x => ids.Contains(x.RootId)).Where(funcWhere).OrderByBatch(orderBy).ToListAsync();
            //将分页数据映射成DTO
            var listDto = _mapper.Map<IEnumerable<ArticleCommentDto>>(page.ToList());
            foreach (var item in listDto)
            {
                var child = childrenList.Where(t => t.RootId == item.Id).ToList();
                item.Children = _mapper.Map<IEnumerable<ArticleCommentDto>>(child).ToList();
            }
            var pageList = PaginationList<ArticleCommentDto>.Create(pageIndex, pageSize, page.TotalCount, listDto.ToList());
            return pageList;
        }

        /// <summary>
        /// 查询前几条数据
        /// </summary>
        public async Task<IEnumerable<ArticleCommentDto>> QueryListAsync(int top, Expression<Func<ArticleComment, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //获取第一级的分页数据
            var result = _context.Set<ArticleComment>().Include(x => x.User).ThenInclude(x => x!.Member)
                .Where(x => x.ParentId == 0)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            if (top > 0) result = result.Take(top);
            var parentList = await result.ToListAsync();
            //所有主键
            List<long> ids = parentList.Select(t => t.Id).ToList();
            var list = _mapper.Map<IEnumerable<ArticleCommentDto>>(parentList);
            //查询子集数据
            var childrenList = await _context.Set<ArticleComment>().Where(x => ids.Contains(x.RootId)).Where(funcWhere).ToListAsync();
            //是否有子集
            if (childrenList != null)
            {
                foreach (var item in list)
                {
                    var child = childrenList.Where(t => t.RootId == item.Id).ToList();
                    item.Children= _mapper.Map<IEnumerable<ArticleCommentDto>>(child).ToList();
                }
            }
            return list;
        }

        /// <summary>
        /// 查询前几条数据(返回树)
        /// </summary>
        public async Task<IEnumerable<ArticleCommentDto>> QueryListTreeAsync(int top, Expression<Func<ArticleComment, bool>> funcWhere, string orderBy, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            //获取第一级的分页数据
            var result = _context.Set<ArticleComment>().Include(x => x.User).ThenInclude(x => x!.Member)
                .Where(x => x.ParentId == 0)
                .Where(funcWhere).OrderByBatch(orderBy);//调用Linq扩展类排序
            if (top > 0) result = result.Take(top);
            var parentList = await result.ToListAsync();
            //所有主键
            List<long> ids = parentList.Select(t => t.Id).ToList();
            //查询子集数据
            var childrenList = await _context.Set<ArticleComment>().Where(x => ids.Contains(x.RootId)).Where(funcWhere).ToListAsync();
            //是否有子集
            if (childrenList != null)
            {
                foreach (var item in parentList)
                {
                    childrenList.Add(item);
                }
            }
            else
            {
                childrenList = parentList;
            }
            var list = await GetChilds(childrenList, 0, 0, orderBy);
            return list;
        }

        /// <summary>
        /// 获取记录总数量
        /// </summary>
        public async Task<int> QueryCountAsync(Expression<Func<ArticleComment, bool>> funcWhere, WriteRoRead writeAndRead = WriteRoRead.Read)
        {
            _context = _contextFactory.CreateContext(writeAndRead);//连接数据库
            return await _context.Set<ArticleComment>().Where(funcWhere).CountAsync();
        }

        /// <summary>
        /// 迭代循环返回目录树(私有方法)
        /// </summary>
        private async Task<List<ArticleCommentDto>> GetChilds(IEnumerable<ArticleComment> listData, long parentId, int classLayer, string orderBy)
        {
            classLayer++;
            List<ArticleCommentDto> listDto = new List<ArticleCommentDto>();
            IEnumerable<ArticleComment> models = listData.Where(x => x.ParentId == parentId).OrderByBatch(orderBy);//查找并排序
            foreach (ArticleComment modelt in models)
            {
                ArticleCommentDto modelDto = _mapper.Map<ArticleCommentDto>(modelt);
                modelDto.ClassLayer = classLayer;
                modelDto.Children.AddRange(
                    await GetChilds(listData, modelt.Id, classLayer, orderBy)
                );
                listDto.Add(modelDto);
            }
            return listDto;
        }
    }
}
